﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;

namespace SPHelper
{
	public class Cache
	{
		public static string FormatKey(string key)
		{
			if (!string.IsNullOrEmpty(key))
			{
				// lower and trim
				key = key.ToLower().Trim();

				// remove clear cache url param
				key = key.Replace("&isclearcache=true", "").Replace("?isclearcache=true", "").Replace("&isclearcache=false", "").Replace("?isclearcache=false", "");
			}
			return key;
		}


		/// <summary>
		/// Determine if key exists in cache
		/// </summary>
		/// <param name="current"></param>
		/// <param name="key"></param>
		/// <returns></returns>
		public static bool IsExist(System.Web.Caching.Cache cache, string key)
		{
			bool isExist = false;
			try
			{
				// init
				if (cache == null) { throw new Exception("Cache passed is null"); }
				if (string.IsNullOrEmpty(key)) { throw new Exception("Cache key passed is null"); }
				string _key = FormatKey(key);


				if (cache != null && cache[_key] != null)
				{
					isExist = true;
				}
			}
			catch (Exception ex)
			{
				Log.WriteError("fdgghcghcxdfft", ex, "key: " + key);
			}
			return isExist;
		}

		/// <summary>
		/// Get string from cache
		/// </summary>
		/// <param name="current"></param>
		/// <param name="key"></param>
		/// <returns></returns>
		public static string GetCache(System.Web.Caching.Cache cache, string key)
		{
			string o = null;
			try
			{
				// init
				if (cache == null) { throw new Exception("Cache passed is null"); }
				if (string.IsNullOrEmpty(key)) { throw new Exception("Cache key passed is null"); }
				string _key = FormatKey(key);


				if (IsExist(cache, _key))
				{
					o = cache[_key].ToString();
				}
			}
			catch (Exception ex)
			{
				Log.WriteError("dxfvhjyutu6deswawwaes", ex, "key: " + key);
				o = null;
			}
			return o;
		}

		/// <summary>
		/// Get a READ ONLY copy of the cache for enumerating
		/// </summary>
		/// <param name="cache"></param>
		/// <param name="keySubstring"></param>
		/// <returns></returns>
		public static Dictionary<string, object> GetCacheCollection(System.Web.Caching.Cache cache, string keySubstring)
		{
			Dictionary<string, object> cacheCollection = null;
			try
			{
				// init
				if (!string.IsNullOrEmpty(keySubstring)) { keySubstring = keySubstring.ToLower().Trim(); }
				cacheCollection = new Dictionary<string,object>();


				if (cache != null)
				{
					int loopCheck = 0; int maxLoop = 100000;
					System.Collections.IDictionaryEnumerator _cache = cache.GetEnumerator();
					while (_cache.MoveNext())
					{
						if (loopCheck > maxLoop) { break; }
						loopCheck++;

						string currentKey = _cache.Key.ToString();
						if (string.IsNullOrEmpty(keySubstring) || currentKey.ToLower().Contains(keySubstring))
						{
							cacheCollection.Add(currentKey, cache[currentKey]);
						}
					}
				}
			}
			catch (Exception ex)
			{
				Log.WriteError("tdhrtytrjshew5thnddzfzdg", ex);
				cacheCollection = null;
			}
			return cacheCollection;
		}

		/// <summary>
		/// Add string to cache, will remove existing cache if already exists
		/// </summary>
		/// <param name="current"></param>
		/// <param name="key"></param>
		/// <param name="valueToCache"></param>
		/// <param name="numberOfMinutesToCache"></param>
		public static void AddCache(System.Web.Caching.Cache cache, string key, string valueToCache, 
			int numberOfMinutesToCache)
		{
			try
			{
				// init
				if (cache == null) { throw new Exception("Cache passed is null"); }
				if (string.IsNullOrEmpty(key)) { throw new Exception("Cache key passed is null"); }
				if (numberOfMinutesToCache == 0) { numberOfMinutesToCache = 15; }
				string _key = FormatKey(key);


				if (IsExist(cache, _key))
				{
					// remove the key and then re-create
					cache.Remove(_key);
				}

				cache.Add(_key, valueToCache, null, DateTime.Now.AddMinutes(numberOfMinutesToCache),
					System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Normal,
					null);
			}
			catch (Exception ex)
			{
				Log.WriteError("u8oydtsdrgsaasee", ex, "key: " + key);
			}
		}


		/// <summary>
		/// output an HTML comment on cache create and expire date
		/// </summary>
		/// <param name="cacheExpireDate"></param>
		/// <returns></returns>
		public static string CacheComment(DateTime cacheExpireDate)
		{
			string o = string.Empty;
			try
			{
				if (cacheExpireDate != null && cacheExpireDate != DateTime.MinValue)
				{
					o = "\n\n<!-- Cached on: " + DateTime.Now.ToShortDateString()
						+ " " + DateTime.Now.ToShortTimeString() + ". Cache expires on:"
						+ " " + cacheExpireDate.ToShortDateString() + " "
						+ " " + cacheExpireDate.ToShortTimeString() + " -->\n\n";
				}
			}
			catch (Exception ex)
			{
				Log.WriteError("u98lfykutdhdrsersryd", ex);
				o = null;
			}
			return o;
		}

		/// <summary>
		/// output an HTML comment on cache create and expire date
		/// </summary>
		/// <param name="minutesUtillExpire"></param>
		/// <returns></returns>
		public static string CacheComment(int minutesUtillExpire)
		{
			string o = string.Empty;
			try
			{
				if (minutesUtillExpire > 0)
				{
					DateTime cacheExpireDate = DateTime.Now.AddMinutes(minutesUtillExpire);
					o = CacheComment(cacheExpireDate);
				}
			}
			catch (Exception ex)
			{
				Log.WriteError("u9futdfsdfsrddtxdfht", ex);
				o = null;
			}
			return o;
		}

		/// <summary>
		/// Delete cached objects
		/// </summary>
		/// <param name="current"></param>
		/// <param name="keySubstring">a substring of the key to delete. 
		/// For instance, to delete all cached pages for a site, pass its domain name</param>
		/// <returns></returns>
		public static int DeleteCache(System.Web.Caching.Cache cache, string keySubstring)
		{
			int numberItemsDeleted = 0;
			try
			{
				// init
				if (cache == null) { throw new Exception("Cache passed is null"); }
				if (string.IsNullOrEmpty(keySubstring)) { throw new Exception("Cache key substring passed is null"); }
				keySubstring = keySubstring.ToLower().Trim();


				// get all cache that matches keyword
				Dictionary<string, object> cacheToDelete = GetCacheCollection(cache, keySubstring);

				// now delete cache
				foreach (KeyValuePair<string, object> c in cacheToDelete)
				{
					cache.Remove(c.Key);
					numberItemsDeleted++;
				}
				
			}
			catch (Exception ex)
			{
				Log.WriteError("67irraewwaawwarzdxfhxft", ex, "key substring: " + keySubstring);	
			}
			return numberItemsDeleted;
		}


		/// <summary>
		/// Determine if need to recreate cache
		/// </summary>
		/// <param name="cache"></param>
		/// <param name="cacheKey"></param>
		/// <param name="fullUrl"></param>
		/// <returns></returns>
		public static bool IsClearCache(System.Web.Caching.Cache cache, string cacheKey, string fullUrl)
		{
			bool isRecreateCache = true;
			bool isDebug = false;
			try
			{
				// init
				if (cache != null && !string.IsNullOrEmpty(cacheKey) && !string.IsNullOrEmpty(fullUrl))
				{
					if (isDebug) { SPHelper.Log.WriteInformation("starting to check cache info, key: " + cacheKey + " full url: " + fullUrl); }

					// url param passed?
					if (fullUrl.ToLower().Contains("isclearcache"))
					{
						if (isDebug) { SPHelper.Log.WriteInformation("is clear cache param defined"); }
						isRecreateCache = Convert.ToBoolean(Utilities.GetUrlParamValue("isclearcache", fullUrl));
						if (isDebug) { SPHelper.Log.WriteInformation("isClearCache param value is: " + isRecreateCache + " with param value string:" + Utilities.GetUrlParamValue("isclearcache", fullUrl)); }
						// param value is false, yet no cache exists, force re-create
						if (!isRecreateCache && !IsExist(cache, cacheKey))  
						{ 
							isRecreateCache = true;
							if (isDebug) { SPHelper.Log.WriteInformation("isClearCache param value is false, yet cached info doesn't already exist. Will force page to create new cache entry"); }
						}
					}
					// see if already exists in cache
					else if (IsExist(cache, cacheKey)) 
					{
						isRecreateCache = false;
						if (isDebug) { SPHelper.Log.WriteInformation("isClearCache url param not passed, and content already cached. Will use cache"); }
					}
				}

				// dont do any caching on edit form
				if (!string.IsNullOrEmpty(fullUrl) && fullUrl.ToLower().Contains("editform.aspx"))
				{
					isRecreateCache = false;
					if (isDebug) { SPHelper.Log.WriteInformation("Edit form, will force content to use what is cached or nothing at all"); }
				}
			}
			catch (Exception ex)
			{
				Log.WriteError("6r7irthsrsaaewraew", ex, " cache key: " + cacheKey + " url: " + fullUrl);
			}
			return isRecreateCache;
		}

	}
}
